package com.efrei.schoolmanager.model.hibernate.dao;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;

import com.efrei.schoolmanager.exceptions.LogicException;
import com.efrei.schoolmanager.model.dao.HibernateDAO;
import com.efrei.schoolmanager.model.obj.Classe;
import com.efrei.schoolmanager.model.obj.Eleve;
import com.efrei.schoolmanager.model.obj.Matiere;
import com.efrei.schoolmanager.model.obj.Note;

/**
 * DAO pour les notes avec hibernate
 */
public class NoteDAO extends HibernateDAO<Note> {

	public NoteDAO(Session session) {
		super(session, Note.class);
	}

	/**
	 * recupere les notes en base pour une Classe donnée. <br/>
	 * utilise le nom et l'année de promotion de la Classe existante.
	 * 
	 * @param classe
	 * @return les notes selon la classe donnée
	 */
	@SuppressWarnings("unchecked")
	public List<Note> getNoteByClasse(Classe classe) {
		Session session = getSession();
		// creation de la requete hql ET demande de la liste
		String hql = "SELECT n from Note n JOIN n.classe WHERE n.classe.nom = :nom AND n.classe.promotion = :promotion";
		Query request = session.createQuery(hql)
				.setString("nom", classe.getNom())
				.setInteger("promotion", classe.getPromotion());
		return request.list();
	}

	/**
	 * créer une nouvelle note en allant chercher en base les bonnes références.
	 * Toutes les autres doivent exister en base !!
	 * 
	 * @param matricule
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Note create(String matricule, int promotion, String classeNom,
			String matiereNom, int periode, int numControle, float note) {
		Session session = getSession();
		// la strategie avec les load est d'avoir un objet pour insérer mais ne
		// récupére pas les données
		// recuperation de l'id de l'eleve
		Query getEleve = session.createQuery(
				"SELECT e.eleveId FROM Eleve e WHERE e.matricule = :matricule")
				.setString("matricule", matricule);
		Eleve eleve = (Eleve) session.load(Eleve.class,
				((List<Integer>) getEleve.list()).get(0));

		// recuperation de la classe
		Query getClasse = session
				.createQuery(
						"SELECT c.classeId FROM Classe c WHERE c.nom = :nom AND c.promotion = :promotion")
				.setInteger("promotion", promotion).setString("nom", classeNom);
		Classe classe = (Classe) session.load(Classe.class,
				((List<Integer>) getClasse.list()).get(0));

		// recuperation de la matiere
		Query getMatiere = session.createQuery(
				"SELECT matiereId FROM Matiere m WHERE m.nom = :nom")
				.setString("nom", matiereNom);
		Matiere matiere = (Matiere) session.load(Matiere.class,
				((List<Integer>) getMatiere.list()).get(0));

		// creation du proxy de la note et save
		Note nouvelleNote = new Note(eleve, classe, matiere, periode,
				numControle, note);
		session.save(nouvelleNote);

		return nouvelleNote;
	}

	/**
	 * update la note (float) sachant qu'une note pour les mêmes foreign key /
	 * periode / numControle existe déjà
	 * 
	 * @param matricule
	 * @param promotion
	 * @param classeNom
	 * @param matiereNom
	 * @param periode
	 * @param numControle
	 * @param note
	 *            valeur a updaté
	 * @return
	 * @throws LogicException
	 */
	public Note updateNote(String matricule, int promotion, String classeNom,
			String matiereNom, int periode, int numControle, float note)
			throws LogicException {
		Session session = getSession();
		Note noteRef = (Note) (session
				.createQuery(
						"SELECT n FROM Note n JOIN n.eleve e JOIN n.classe c JOIN n.matiere m"
								+ " WHERE n.periode = :periode"
								+ " AND n.numControle = :numControle"
								+ " AND c.nom = :classeNom"
								+ " AND m.nom = :matiereNom"
								+ " AND e.matricule = :matricule"
								+ " AND c.promotion = :promotion")
				// affectation des valeurs à la requete
				.setInteger("periode", periode)
				.setInteger("numControle", numControle)
				.setString("matricule", matricule)
				.setInteger("promotion", promotion)
				.setString("classeNom", classeNom)
				.setString("matiereNom", matiereNom)
		// et on recupere la 1e et seule note
				.list()).get(0);
		noteRef.setNote(note);
		session.update(noteRef);
		return noteRef;
	}
}
